package com.rankeiot.platform;

import com.rankeiot.core.EasyCorePlugin;
import com.rankeiot.core.MenuManager;
import com.rankeiot.core.Module;
import com.rankeiot.core.config.ConfigItemMeta;
import com.rankeiot.core.config.ConfigManager;
import com.rankeiot.core.data.MenuItem;
import com.rankeiot.core.event.ConfigChangeEvent;
import com.rankeiot.core.sqltoy.JsonTypeHandler;
import com.rankeiot.core.util.LocaleUtil;
import com.rankeiot.core.util.StringUtil;
import com.rankeiot.platform.config.*;
import com.rankeiot.platform.controller.DataEaseController;
import com.rankeiot.platform.dicts.Gender;
import com.rankeiot.platform.inner.DBOverTimeSqlHandler;
import com.rankeiot.platform.service.ClientMessageService;
import com.rankeiot.platform.service.IFileStoreService;
import com.rankeiot.platform.service.LocalFileStoreService;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;
import org.sagacity.sqltoy.SqlToyContext;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import java.util.List;
import java.util.Locale;


/**
 * 平台模块
 */
@Slf4j
@Configuration
@EnableScheduling
@EnableWebSocket
@Import(DocConfig.class)
@ComponentScan(basePackages = {"com.rankeiot.platform.service", "com.rankeiot.platform.controller"})
public class PlatformModule implements Module, WebMvcConfigurer, WebSocketConfigurer {
    public static String serverId = "";
    public static String localhost;

    @Value("${spring.profiles.active:default}")
    private String active;
    @Value("${files.path:files}")
    private String filesPath = "files";
    @Value("${application.login_page:login.vue}")
    private String loginPage = "login.vue";
    @Value("${application.home_page:}")
    private String homePage = null;

    @Bean
    public ClientMessageService clientMessageService() {
        return new ClientMessageService();
    }

    @Bean
    public DataEaseController.DataEaseWebSocketHandler dataEaseWebSocketHandler() {
        return new DataEaseController.DataEaseWebSocketHandler();
    }

    @Override
    public String name() {
        return LocaleUtil.encode("系统管理", "Platform");
    }

    private void addConfigItem(String name, String title, String defaultValue) {
        List<ConfigItemMeta> metas = ConfigManager.getMetas().get(name());
        ConfigItemMeta meta = new ConfigItemMeta();
        meta.setSn(this.getClass().getName() + "." + name);
        meta.setControl("Input");
        meta.setTitle(title);
        meta.setFront(true);
        meta.setMemo("默认值为:" + defaultValue);
        meta.setDefaultValue(defaultValue);
        metas.add(meta);
    }

    @Override
    public void start(ApplicationContext applicationContext) {

        //注册菜单
        regMenu(PlatformMenu.class);

        if (PlatformApplication.pluginMode) {
            MenuItem menuItem = new MenuItem(PlatformMenu.PLUGINS, LocaleUtil.encode("应用管理", "Applications"), "jeicon-web-switch", 11);
            menuItem.setPath("platform/plugins.vue");
            menuItem.setParent(PlatformMenu.ID);
            MenuManager.addMenu(menuItem);
        }
        //添加首页菜单
        //首页菜单没有parent,排序靠前
//        @Menu(value = "首页", path = "home.vue", icon = "h-icon-home",order=-10,parent = "")
//        String Home = "Home";
        MenuItem menuItem = new MenuItem("Home", LocaleUtil.encode("首页", "Home"), "h-icon-home", -10);
        menuItem.setPath(StringUtil.isEmpty(homePage) ? "home.vue" : homePage);
        MenuManager.addMenu(menuItem);

        //注册配置项
        regConfigs(PlatformConfig.class);

        //登录页配置项
        addConfigItem("LoginPage", LocaleUtil.encode("登录页", "LoginPage"), loginPage);

        //LoginPage
        ConfigManager.register(LocaleUtil.encode("高德地图","Gaode Map"), AMapConfig.class);
        ConfigManager.register(LocaleUtil.encode("微信开放平台","WeChat Open Platform"), WxOpenConfig.class);
        ConfigManager.register(LocaleUtil.encode("微信小程序", "WeChat Mini Program"), WxMpConfig.class);
        ConfigManager.register(LocaleUtil.encode("数据看板", "Data Board"), DataEaseConfig.class);
        ConfigManager.register(LocaleUtil.encode("登录页面配置","Login Page"), LoginConfig.class);
        //注册固定字典项
        regFixedDict(Gender.class);

    }

    @ConditionalOnMissingBean(RestTemplate.class)
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @ConditionalOnMissingBean(IFileStoreService.class)
    @Bean
    IFileStoreService fileStoreService() {
        return new LocalFileStoreService(filesPath);
    }

    @Autowired(required = false)
    public void initSqltoy(SqlToyContext context, SqlToyLazyDao dao, Environment env) {
        if (context.getTypeHandler() == null) {
            context.setTypeHandler(new JsonTypeHandler());
        }
        if (context.getOverTimeSqlHandler() == null) {
            context.setOverTimeSqlHandler(new DBOverTimeSqlHandler(dao));
        }
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CrossDomainInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
               if(EasyCorePlugin.hasDataSource){
                   response.sendError(404);
                   return false;
               }
               return true;
            }
        }).addPathPatterns("/install.html");
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(clientMessageService(), "/ws")
                .setAllowedOrigins("*");
        registry.addHandler(dataEaseWebSocketHandler(), "/ease/websocket/**")
                .setAllowedOrigins("*");
    }

    public class CrossDomainInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String origin = request.getHeader("Origin");
            if (origin == null) {
                return true;
            }
            String domain = PlatformConfig.DomainAllow.strValue();
            if (StringUtil.isEmpty(domain)) {
                return true;
            }
            if ("*".equals(domain) || domain.indexOf(origin) > -1) {
                response.setHeader("Access-Control-Expose-Headers", "token");
                response.setHeader("Access-Control-Allow-Headers", "Content-Type,token,apptype");
                response.setHeader("Access-Control-Max-Age", "1800");
                response.setHeader("Access-Control-Allow-Origin", origin);
                response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT");
                response.setHeader("Access-Control-Allow-Credentials", "true");
            }
            if ("OPTIONS".equals(request.getMethod())) {
                response.setStatus(202);
                return false;
            }
            return true;
        }
    }

    @EventListener
    public void handleConfigChangeEvent(ConfigChangeEvent event) {
        if (event.getChangeKeys().contains(PlatformConfig.DefaultLang.fullName())) {
            String lang = PlatformConfig.DefaultLang.strValue();
            if ("en".equals(lang)) {
                LocaleUtil.setDefaultLocal(Locale.ENGLISH);
            } else if("zh".equals(lang)) {
                LocaleUtil.setDefaultLocal(Locale.CHINESE);
            }
            log.info("change default language:"+lang);
        }
    }
//    @ConditionalOnMissingBean(JFinalViewResolver.class)
//    @Bean
//    public JFinalViewResolver jFinalViewResolver(){
//        JFinalViewResolver jfr=new JFinalViewResolver();
//        jfr.setSuffix(".html");
//        jfr.setBaseTemplatePath("/static/");
//        jfr.setContentType("text/html;charset=UTF-8");
//        jfr.setOrder(0);
//        jfr.getEngine().removeDirective("json");
//        jfr.addDirective("json", JsonTag.class);
//        jfr.setToClassPathSourceFactory();
//        if("dev".equals(active)){
//            jfr.setDevMode(true);
//        }
//        return jfr;
//    }
}
